<template>
    <div style="height: 100%;width: 100%;">
        <div style="height: 100%;display: flex;flex-direction: row;">
            <div style="flex: 0 0 20%;overflow: hidden;">
                <!-- 侧栏菜单 -->
                <!--  append-to-body="true" 子菜单挂载到body，脱离父级布局 -->
                <el-menu
                        mode="vertical"
                        append-to-body="true"
                        style="height: 100%;background-color:#f2f6fc; "
                >
                    <!-- 子菜单 -->
                    <el-submenu v-for="(type, index) in typeList" :key="type" :index="String(index)">
                        <template slot="title">
                            <i class="el-icon-s-grid"></i>
                            <span>{{type}}</span>
                        </template>
                        <el-menu-item-group>
                            <el-menu-item
                                    v-for="item in libraryList[type]"
                                    :key="item.id"
                                    class="library-item">
                                <div draggable="true" @dragstart="dragToBoardStart">
                                    <!--不能换，涉及到下面（dragToBoardStart）的取值-->
                                    <img :src="item.pic" :alt="item.name" draggable="false" style="width: 30px; height: 30px">
                                    <span>{{item.name}}</span>
                                </div>
                            </el-menu-item>
                        </el-menu-item-group>
                    </el-submenu>
                </el-menu>
            </div>
            <div style="flex: 1;position: relative;">
                <!--右上角操作按钮-->
                <div style="position: absolute;top:5px;right:5px;">
                    <el-button type="primary" @click="saveTopo">保存拓扑</el-button>
                    <el-button type="warning" @click="clearTopo">删除拓扑</el-button>
                </div>
                <!-- topo中的节点的右键菜单 -->
                <Context-Menu :position="position" v-if="showMenu" @menuClick="clickMenuItem" />
                <!-- 画板 -->
                <svg
                        style="height: 99%;width: 100%;"
                        ondragover="return false"
                        @drop="dropToBoard"
                        oncontextmenu="return false"
                        @click.left.stop.prevent="closeContextMenu">
                    <!-- 正在连接的线 -->
                    <line
                            :x1="connecting.x1" :y1="connecting.y1"
                            :x2="connecting.x2" :y2="connecting.y2"
                            style="stroke:rgb(255,0,0);stroke-width:2">
                    </line>
                    <!-- 已连接的线 -->
                    <line
                            v-for="(item, index) in lines"
                            :key="index"
                            :x1="item.x1" :y1="item.y1"
                            :x2="item.x2" :y2="item.y2"
                            style="stroke:rgb(255,0,0);stroke-width:2">
                    </line>
                    <!-- topo图上的节点 -->
                    <g
                            v-for="(item, index) in topoNodes"
                            :key="item.id"
                            @mousedown.left.stop.prevent="moveAndLink(index, $event)"
                            @click.right.stop.prevent="nodeMenu(index, $event)">
                        <image :xlink:href="item.pic" width="50px" height="50px" :x="item.x" :y="item.y"></image>
                        <text :x="item.x + 25" :y="item.y + 66" style="text-anchor: middle; user-select: none;">{{item.name}}</text>
                    </g>
                </svg>
            </div>
        </div>
    </div>
</template>
<script>
    import nodeData from "./t001/data/nodeData.js";
    import ContextMenu from "./t001/ContextMenu.vue";
    export default {
        components:{ContextMenu},
        data(){
            return {
                //菜单相关参数
                libraryList: {}, // 左侧节点库的节点数据
                typeList: [], // 节点分类
                //右键菜单参数
                position: {x: 0, y: 0}, // 右键菜单的位置
                showMenu: false, // 控制右键菜单的显示与否
                indexOfMenu: null, // 表示在哪个节点上点击了右键菜单
                //拓扑图涉及的参数
                move: true, // 操作模式，默认为移动。可切换为连接模式
                topoNodes: [], // topo图中的节点
                topoLinks: [], // topo图中的连线
                connecting:{ // 显示正在连接的线条
                    x1: 0,
                    y1: 0,
                    x2: 0,
                    y2: 0
                },
            }
        },
        mounted(){
            this.libraryList = nodeData;
            this.typeList = Object.keys(this.libraryList);
        },
        methods:{
            // 从左边的节点库拖出节点
            dragToBoardStart (e) {
                // 设置拖出的数据
                e.dataTransfer.setData('text/plain', JSON.stringify({
                    pic: e.target.children[0].src,
                    name: e.target.children[1].innerText
                }));
                e.dataTransfer.effectAllowed = "copy" // 设置拖的操作为复制操作
            },
            // 节点拖放到topo图区域，即新建节点
            dropToBoard (e) {
                const content = JSON.parse(e.dataTransfer.getData('text/plain')) // 接收来自拖出的内容,并还原为对象
                const date = new Date()
                let node = {
                    id: date.getTime(), // 用时间戳生成唯一id，Symbol类型的id不能存储到本地
                    pic: content.pic, // 图片
                    name: content.name, // 默认显示名称，可修改
                    x: e.layerX, // 横坐标
                    y: e.layerY, // 纵坐标
                }
                this.topoNodes.push(node)
                console.log("this.topoNodes",this.topoNodes);
            },
            // 执行右键菜单的功能
            clickMenuItem (option) {
                // 关闭右键菜单
                this.showMenu = false;
                // 连接功能
                if (option === 'link') {
                    // 设置为连线模式
                    this.move = false;
                    // 创建连线
                    this.connecting = {
                        x1: this.topoNodes[this.indexOfMenu].x + 20,
                        y1: this.topoNodes[this.indexOfMenu].y + 20,
                        x2: this.topoNodes[this.indexOfMenu].x + 20,
                        y2: this.topoNodes[this.indexOfMenu].y + 20
                    };
                    // 连线终点跟随鼠标
                    document.onmousemove = (e) => {
                        this.connecting.x2 = e.layerX;
                        this.connecting.y2 = e.layerY
                    }
                }
                // 重命名功能
                if (option === 'rename') {
                    this.$prompt('请输入新名称', '重命名', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        inputPattern: /\S/,
                        inputErrorMessage: '名称不能为空'
                    }).then(({ value }) => {
                        this.topoNodes[this.indexOfMenu].name = value
                    })
                }
                // 删除功能
                if (option === 'delete') {
                    this.$confirm(`是否删除节点 "${this.topoNodes[this.indexOfMenu].name}"`, '删除节点', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        this.topoNodes.splice(this.indexOfMenu, 1)
                    })
                }
            },
            // 点击空白地方，关闭右键菜单，取消连线模式
            closeContextMenu () {
                // 关闭右键菜单
                this.position = {x: 0, y: 0};
                this.showMenu = false;
                this.indexOfMenu = null;
                // 取消连线模式
                this.move = true;
                this.connecting = {
                    x1: 0,
                    y1: 0,
                    x2: 0,
                    y2: 0
                };
                document.onmousemove = null
            },
            // 显示topo图上的节点的右键菜单
            nodeMenu (index, e) {
                this.position = {x: e.offsetX, y: e.offsetY}
                this.showMenu = true
                this.indexOfMenu = index
            },
            // 移动topo图中的节点，连接节点
            moveAndLink (index, e) {
                console.log("moveAndLink",this.move);
                // 判断当前模式
                if (this.move) {
                    // 移动模式
                    const layerX = e.layerX - this.topoNodes[index].x
                    const layerY = e.layerY - this.topoNodes[index].y
                    document.onmousemove = (e) => {
                        this.topoNodes[index].x = e.layerX - layerX
                        this.topoNodes[index].y = e.layerY - layerY
                    }
                    document.onmouseup = () => {
                        document.onmousemove = null
                        document.onmouseup = null
                    }
                } else {
                    // 连线模式
                    this.topoLinks.push({
                        startNodeId: this.topoNodes[this.indexOfMenu].id,
                        endNodeId: this.topoNodes[index].id,
                        startInterface: 'fa0/1',
                        endInterface: 'fa0/1'
                    })
                    this.connecting = { // 重置正在连接的线
                        x1: 0,
                        y1: 0,
                        x2: 0,
                        y2: 0
                    }
                    document.onmousemove = null // 重置鼠标移动事件
                    this.move = true // 重置为移动模式
                }
            },
            // 保存Topo
            saveTopo () {
                localStorage.topoNodes = JSON.stringify(this.topoNodes)
                localStorage.topoLinks = JSON.stringify(this.topoLinks)
                this.$alert('保存成功')
                console.log("this.topoNodes",this.topoNodes);
                console.log("this.topoLinks",this.topoLinks);
            },
            clearTopo () {
                this.$confirm('是否清空当前拓扑图？', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    localStorage.removeItem('topoNodes')
                    localStorage.removeItem('topoLinks')
                    this.topoNodes = []
                    this.topoLinks = []
                })
            },
        },
        computed: {
            // 动态计算节点间的连线
            lines () {
                let hash = {}
                const OFFSET = 20
                this.topoNodes.forEach((node, index) => {
                    hash[node.id] = index
                })
                return this.topoLinks.map(item => {
                    const startNode = this.topoNodes[hash[item.startNodeId]]
                    const endNode = this.topoNodes[hash[item.endNodeId]]
                    return {
                        x1: startNode.x + OFFSET,
                        y1: startNode.y + OFFSET,
                        x2: endNode.x + OFFSET,
                        y2: endNode.y + OFFSET,
                        startInterface: item.startInterface,
                        endInterface: item.endInterface
                    }
                })
            }
        },
    }
</script>